use anyhow::Result;
use smol::io::AsyncWriteExt;
use smol::net::{TcpListener, TcpStream};

use crate::config::{self, CONFIG};
use crate::dubbo;

pub(crate) async fn listen() {
    let cfg = (*CONFIG).load();
    let listener = TcpListener::bind(&cfg.own.addr).await.unwrap();
    log::info!("listen on {}", &cfg.own.addr);

    loop {
        match listener.accept().await {
            Ok((mut gateway_stream, addr)) => smol::spawn(async move {
                log::info!("Receive request from {}", addr);
                if let Err(e) = handle(&mut gateway_stream).await {
                    log::error!("handle fail: {:?}", e);
                }
            })
            .detach(),
            Err(e) => {
                log::error!("listener.accept fail: {:?}", e);
                continue;
            }
        }
    }
}

async fn handle(gateway_stream: &mut TcpStream) -> Result<()> {
    let cfg = (*CONFIG).load();
    let mut dubbo_stream = TcpStream::connect(&cfg.provider.addr).await?;
    log::info!("connect to {}", &cfg.provider.addr);

    conv(gateway_stream, &mut dubbo_stream).await?;

    dubbo_stream.flush().await?;
    dubbo_stream.close().await?;

    Ok(())
}

async fn conv(_gateway_stream: &mut TcpStream, dubbo_stream: &mut TcpStream) -> Result<()> {
    //TODO when get reload request, reload config
    config::reload().await;
    dubbo_stream.write_all(&[]).await?;
    Ok(())
}
